using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace LS.SimpleInput
{
    public partial class UserInputEventSystem
    {
        public event Action<Gesture> OnAnyGestrue;
        public event Action<Gesture> OnAnyGestrueCancle;
        public event Action<Gesture> OnInput;
        public event Action<Gesture> OnInputStart;
        public event Action<Gesture> OnInputEnd;
        public event Action<Gesture> OnInputCancle;
        public event Action<Gesture> OnSimpleTap;
        public event Action<Gesture> OnDoubleTap;
        public event Action<Gesture> OnLongTapStart;
        public event Action<Gesture> OnLongTap;
        public event Action<Gesture> OnLongTapEnd;
        public event Action<Gesture> OnLongTapCancle;
        public event Action<Gesture> OnSwipeStart;
        public event Action<Gesture> OnSwipe;
        public event Action<Gesture> OnSwipeEnd;
        public event Action<Gesture> OnSwipeCancle;

        public event Action<UserInputEventSystem> AfterGestureUpdate;

        private UserInputSetting m_Setting;
        private List<Inputer> m_Inputers = new List<Inputer>();
        private List<PointInputer> m_TempPointInputers = new List<PointInputer>();

        private Dictionary<Inputer, SingleInputerGestureStates> m_SingleInputerGestureStates = new Dictionary<Inputer, SingleInputerGestureStates>();

        public MouseLeftButtonInputer MouseLeftButton
        {
            get;
            private set;
        }

        public UserInputEventSystem(UserInputSetting setting)
        {
            if (setting == null)
            {
                setting = UserInputSetting.defaultSetting;
            }
            MouseLeftButton = new MouseLeftButtonInputer(setting);

            m_Inputers.Add(MouseLeftButton);

            for (int i = 0; i < m_Inputers.Count; i++)
            {
                if (m_Inputers[i] is PointInputer pi)
                    m_SingleInputerGestureStates.Add(pi, new SingleInputerGestureStates(pi));
            }
        }

        public UserInputEventSystem() : this(null)
        {

        }

        public void Update()
        {
            UpdateInputer();
            UpdateSingleGestures();
            UpdateEvents();
        }

        private void UpdateInputer()
        {
            for (int i = 0; i < m_Inputers.Count; i++)
            {
                var item = m_Inputers[i];
                if (item != null)
                {
                    item.Update();
                }
            }
        }

        private void UpdateSingleGestures()
        {
            m_TempPointInputers.Clear();
            m_TempPointInputers.AddRange(m_Inputers.OfType<PointInputer>());
            for (int i = 0; i < m_TempPointInputers.Count; i++)
            {
                SingleInputerGestureStates singleGestureState = m_SingleInputerGestureStates[m_TempPointInputers[i]];
                singleGestureState.Update();
            }
            m_TempPointInputers.Clear();
        }

        private void UpdateEvents()
        {
            m_TempPointInputers.Clear();
            m_TempPointInputers.AddRange(m_Inputers.OfType<PointInputer>());

            for (int i = 0; i < m_TempPointInputers.Count; i++)
            {
                PointInputer inputer = m_TempPointInputers[i];
                if (inputer.Phase == InputPhase.Began)
                {
                    var gesture = inputer.CreateGesture();
                    SendEvent(EventType.InputStart, gesture, OnInputStart, OnInput, OnAnyGestrue);
                }
                else if (inputer.Phase == InputPhase.Moved || inputer.Phase == InputPhase.Stationary)
                {
                    var ges = inputer.CreateGesture();
                    SendEvent(EventType.InputUpdate, ges, OnInput, OnAnyGestrue);
                }
                else if (inputer.Phase == InputPhase.Ended)
                {
                    var ges = inputer.CreateGesture();
                    SendEvent(EventType.InputEnd, ges, OnInputEnd, OnInput, OnAnyGestrue);
                }
                else if (inputer.Phase == InputPhase.Canceled)
                {
                    var ges = inputer.CreateGesture();
                    SendEvent(EventType.InputCancle, ges, OnInputCancle, OnInput, OnAnyGestrueCancle, OnAnyGestrue);
                }

                SingleInputerGestureStates singleGestureState = m_SingleInputerGestureStates[inputer];

                if (singleGestureState.tap.TriggerThisFrame)
                {
                    var gesture = GestureStateUtility.CreateGesture(singleGestureState.tap, inputer);
                    SendEvent(EventType.SimpleTap, gesture, OnSimpleTap, OnAnyGestrue);
                }

                if (singleGestureState.doubleTap.TriggerThisFrame)
                {
                    var gesture = GestureStateUtility.CreateGesture(singleGestureState.doubleTap, inputer);
                    SendEvent(EventType.DoubleTap, gesture, OnDoubleTap, OnAnyGestrue);
                }

                if (singleGestureState.longTap.TimerBegining)
                {
                    if (singleGestureState.longTap.TimerBeginingThisFrame)
                    {
                        var gesture = GestureStateUtility.CreateGesture(singleGestureState.longTap, inputer);
                        SendEvent(EventType.LongTapStart, gesture, OnLongTapStart, OnLongTap, OnAnyGestrue);
                    }
                    else if (singleGestureState.longTap.TimerBegining)
                    {
                        var gesture = GestureStateUtility.CreateGesture(singleGestureState.longTap, inputer);
                        SendEvent(EventType.LongTap, gesture, OnLongTap, OnAnyGestrue);
                    }
                    else if (singleGestureState.longTap.EndThisFrame)
                    {
                        var gesture = GestureStateUtility.CreateGesture(singleGestureState.longTap, inputer);
                        SendEvent(EventType.LongTapEnd, gesture, OnLongTapEnd, OnLongTap, OnAnyGestrue);
                    }
                    else if (singleGestureState.longTap.CancledThisFrame)
                    {
                        var gesture = GestureStateUtility.CreateGesture(singleGestureState.longTap, inputer);
                        SendEvent(EventType.LongTapCancle, gesture, OnLongTapCancle, OnLongTap, OnAnyGestrue, OnAnyGestrueCancle);
                    }
                }

                //if (singleGestureState.swipe.Phase == InputPhase.Began)
                //{
                //    var gesture = GestureStateUtility.CreateGesture(singleGestureState.doubleTap, inputer);
                //    SendEvent(EventType.DoubleTap, gesture, OnSwipeStart, OnAnyGestrue);
                //}
            }
            m_TempPointInputers.Clear();
        }

        private void SendEvent(EventType eventType, Gesture ges, params Action<Gesture>[] actions)
        {
            ges.eventType = eventType;
            for (int i = 0; i < actions.Length; i++)
            {
                actions[i]?.Invoke(ges);
            }
        }
    }
}
